package edu.asu.sapa.ground.update;

import java.util.ArrayList;

import edu.asu.sapa.Planner;
import edu.asu.sapa.ground.MathForm;
import edu.asu.sapa.ground.Operator;
import edu.asu.sapa.ground.Problem;
import edu.asu.sapa.ground.PropDB;
import edu.asu.sapa.ground.Proposition;
import edu.asu.sapa.ground.State;
import edu.asu.sapa.ground.PropDB.Entry;
import edu.asu.sapa.heuristic.PG;

public class Condition extends Constraint {

	public Proposition p=null;
	public int id=0;
	// either the value that state.value(id) should return for this condition to succeed, or,
	// if the proposition is constant (i.e., state.value(id) would always return the same thing [sans analysis]),
	// then whether or not this condition is never/always satisfied [false/true resp.]
	public boolean value=false; 
	public boolean isConstant=false;

	public final static Condition bottom = new Condition(false);
	public final static Condition top = new Condition(true);

	public Condition() {}
	
	public Condition(Proposition p, int id, boolean value) {
		this.p = p;
		this.id = id;
		this.value = value;
	}

	private Condition(boolean value) {
		this.value = value;
		this.isConstant = true;
	}

	public Condition(Condition c) {
		this.p = c.p;
		this.id = c.id;
		this.isConstant = c.isConstant;
		this.value = c.value;
	}

	public void relaxedUpdate(PG pg, State s, Context c, float time) {
		if (value)
			pg.addGoal(id,time);
	}
	public void relaxedStart(PG pg, State s, Context c, float time) {
		if (value)
			pg.addGoal(id,time);
	}
	public void relaxedFinish(PG pg, State s, Context c, float time) {
	}
	
	public boolean updateBefore(State s, Context c, float time) {
		PropDB db = s.propDB;
		if (!db.readValueAt(id,time,value))
			return false;
		return true;
	}
	
	public boolean updateAfter(State s, Context c, float time) {
		return false;
		/*PropDB db = s.propDB;
		if (!db.readValueAt(id,time,value))
			return false;
		return true;
		*/
	}

	public boolean startBefore(State s, Context c, float time) {
		PropDB db = s.propDB;
		if (!db.readValueBefore(id,time,value))
			return false;
		s.addConstraint(this,c);
		return true;
	}
	
	public boolean startAfter(State s, Context c, float time) {
		PropDB db = s.propDB;
		if (!db.readValueAt(id,time,value))
			return false;
		s.addConstraint(this,c);
		return true;
	}
	
	public boolean finishBefore(State s, Context c, float time) {
		s.removeConstraint(this,c);
		return true;
	}
	
	
	public boolean finishAfter(State s, Context c, float time) {
		s.removeConstraint(this,c);
		return true;
	}
	
	public boolean applicableBefore(State s, Context c) {
		PropDB db = s.propDB;
		float time = s.time;
		if (!db.getValueBefore(id,time,value))
			return false;
		return true;
	}
	
	public boolean applicableAfter(State s, Context c) {
		PropDB db = s.propDB;
		float time = s.time;
		if (!db.getValueAt(id,time,value))
			return false;
		return true;
	}
	
	@Override
	public boolean holdsAt(State s, Context c) {
		PropDB db = s.propDB;
		float time = s.time;
		if (!db.readValueAt(id,time,value))
			return false;
		return true;
	}

	@Override
	public boolean holdsBefore(State s, Context c) {
		PropDB db = s.propDB;
		float time = s.time;
		if (!db.readValueBefore(id,time,value))
			return false;
		return true;
	}
	
	public int compareTo(Condition o) {
		// assert this != null && o != null;
//		if (isConstant || o.isConstant) {
//			if (isConstant && o.isConstant) {
//				if (!value && o.value)
//					return -1;
//				if (value && !o.value)
//					return 1;
//				return 0;
//			}
//			if (isConstant) {
//				if (!value)
//					return -1;
//				return 1;
//			}
//			if (!o.value)
//				return 1;
//			return -1;
//		}
		if (id < o.id)
			return -1;
		if (id > o.id)
			return 1;
		if (value != o.value)
			if (!value)
				return -1;
			else
				return 1;
		return 0;
	}
	
	public int compareTo(Update o) {
		return compareTo((Condition)o);
	}
	
	public String toString() {
		return "(== " + id + " " + value + ")";
	}

	protected final void makeTop() {
		id=0;
		p = Problem.propositions.get(0);
		value = false;
	}
	
	protected final void makeBot() {
		id=0;
		p = Problem.propositions.get(0);
		value = true;
	}
	
	// conditions return whether or not they are conceivably true, 
	// which is a) both dynamic conditions, and b) some static conditions
	public boolean analyzeStatic(float dur) {
		isConstant = false;

		if (p.isConstant) {
			isConstant = true;
			value = (value == p.value);
			id = 0;
			p = Problem.propositions.get(0);
			return value;
		}
		return true;
	}
	
	@Override
	public boolean isFail() {
		return isConstant && !value;
	}
	
	@Override
	public boolean isNoOp() {
		return isConstant && value;
	}
	
	public void removeDependencies(Operator o) {
		p.removeCondition(o.id);
		o.removeCondition(id);
		assert value == true;
	}
	
	public void setDependencies(Operator o) {
		p.addCondition(o.id);
		o.addCondition(id);
		assert value == true;
	}
	
}
